package com.kind.perm.web.system;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.kind.common.client.response.JsonResponseResult;
import com.kind.common.client.response.JsonResponseResultList;
import com.kind.common.contants.Constants;
import com.kind.common.enums.ResponseState;
import com.kind.common.exception.ServiceException;
import com.kind.common.uitls.NumberUtils;
import com.kind.common.uitls.file.FileUtils;
import com.kind.perm.core.system.domain.CoFileDO;
import com.kind.perm.core.system.domain.FileDO;
import com.kind.perm.core.system.service.FileService;
import com.kind.perm.web.common.ResourceUtil;
import com.kind.perm.web.common.controller.BaseController;

/**
 * 
 * 
 * @date:2016年5月12日 上午11:18:52 <br/>
 * @author 李明
 * @version:
 * @since:JDK 1.7
 */
@Controller
@RequestMapping("file")
public class FileController extends BaseController {
	
	@Autowired
	private FileService fileService;
	/**
	 * 文件保存的目录
	 * ResourceUtil.FILE_PATH 是读取的配置文件可以任意的将文件放到指定的目录下
	 */
	private static final String SAVEPATH=ResourceUtil.FILE_PATH+"files";


	/**
	 * 上传文件
	 * @param response
	 * @param request
	 * @return
	 */
	@RequestMapping(value="uploadFile",method=RequestMethod.POST)
	@ResponseBody
	public String uploadFile(HttpServletResponse response, HttpServletRequest request) {
        try {   
	       MultipartHttpServletRequest multipartHttpServletRequest  = (MultipartHttpServletRequest)request;
	        Map<String, MultipartFile> fileMap = multipartHttpServletRequest.getFileMap();
	        StringBuffer str = new StringBuffer();
	        
	        for(Map.Entry<String, MultipartFile> entity:fileMap.entrySet())
	        {
	        	MultipartFile file = entity.getValue();
	        	String uuid=FileUtils.getUUID();//uuid作为保存时的文件名
				String ext=FileUtils.getFileExt(file.getOriginalFilename());//获取文件后缀
				SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");  
		        String ymd = sdf.format(new Date());  
		        String path =File.separator+ ymd + File.separator;  
		        //创建文件夹  
		        String filepath =path+File.separator+uuid+"."+ext;
	            File newfile = new File(SAVEPATH +filepath);    
	            if (!newfile.exists()) {    
	            	newfile.mkdirs();    
	            }    
				file.transferTo(newfile);
				FileDO filedo = new FileDO();
				filedo.setExt(ext);
				filedo.setName(file.getOriginalFilename());
				filedo.setSize(file.getSize());
				filedo.setUuid(uuid);
				filedo.setCreateTime(new Date());
				filedo.setPath(ymd);
				fileService.save(filedo);
				str.append(filedo.getId());
	        }
            
	        return str.toString();

        }catch (ServiceException e){
            e.printStackTrace();
            logger.error(e.getMessage());
        } catch (IllegalStateException e) {
			e.printStackTrace();
			 logger.error(e.getMessage());
		} catch (IOException e) {
			e.printStackTrace();
			 logger.error(e.getMessage());
		}
		return null;
	}
	
	
	/**
	 * 文件下载
	 * @param newName 文件保存时名称
	 * @param name 文件原名
	 * @param ext  文件后缀
	 * @param request  
	 * @param response
	 * @return
	 * @throws Exception
	 */
    @RequestMapping(value = "download/{path}/{newName}/{name}/{ext}")   
    @ResponseBody
    public String down(@PathVariable("path") String path,@PathVariable("newName") String newName,@PathVariable("name") String name,@PathVariable("ext") String ext,HttpServletRequest request,HttpServletResponse response){  
       
    	return FileUtils.down(SAVEPATH+File.separator+path,name, newName, ext, request,response);
        
    }
    
    /**
	 * 文件预览
	 * @param newName 文件保存时名称
	 * @param name 文件原名
	 * @param ext  文件后缀
	 * @param request  
	 * @param response
	 * @return
	 * @throws Exception
	 */
    @RequestMapping(value = "inline/{path}/{newName}/{name}/{ext}")   
    public String inline(@PathVariable("path") String path,@PathVariable("newName") String newName,@PathVariable("name") String name,@PathVariable("ext") String ext,HttpServletRequest request,HttpServletResponse response){  
       
    	return FileUtils.inline(SAVEPATH+File.separator+path, name, newName, ext, request,response);
        
    } 
    
    /**
	 * 文件删除
	 * 删除关联表t_cofile
	 * 删除文件表t_file
	 */
    @RequestMapping(value = "deletefile/{id}")   
    @ResponseBody
    public JsonResponseResult deletefile(@PathVariable("id") Long id,HttpServletRequest request,HttpServletResponse response){  
    	 try {
                if (!NumberUtils.isEmptyLong(id)) {
                	fileService.remove(id);	
                }
                return JsonResponseResult.success();

            }catch (ServiceException e){
                e.printStackTrace();
                logger.error(e.getMessage());
                return JsonResponseResult.build(ResponseState.ERROR_CODE_SERVICE_ERROR.getCode(), e.getMessage());
            }
    	}
    
    
    /**
	 * 文件预览
	 * @param id 文件的id
	 */
    @RequestMapping(value = "getImage/{id}")   
    public String getImage(@PathVariable("id")Long id,HttpServletRequest request,HttpServletResponse response){  
    	FileDO fileDO = fileService.getById(id);
    	return FileUtils.inline(SAVEPATH+File.separator+fileDO.getPath(), fileDO.getName(), fileDO.getUuid(), fileDO.getExt(), request,response);
    }

    /**
  	 * 文件预览
  	 * 通过传递业务的id，找到对应的首个图片返回一个图片的流提供预览
  	 * @param typeid 业务的id
  	 * @param type 业务的对象字符串
  	 * eg:http://localhost:9090/file/getTypeOnlyImage/12/CompanyDO
  	 */
      @RequestMapping(value = "getTypeOnlyImage/{typeId}/{type}")   
      public String getTypeOnlyImage(@PathVariable("typeId")Long typeId,@PathVariable("type")String type,HttpServletRequest request,HttpServletResponse response){
    	 //1.通过业务id 和 type 联合找到到对应的t_file的list
    	 CoFileDO coFileDO = new CoFileDO();
    	 coFileDO.setObjectA(Constants.COFILE_FILE);
    	 coFileDO.setObjectB(type);
    	 coFileDO.setObjectBId(typeId);
    	 List<FileDO> fileDOlist =  fileService.getFileDOlistByCoFileDO(coFileDO);
    	  
    	 FileDO fileDO = new FileDO();
    	 //2.找到第一个t_file返回到前台
    	 if(fileDOlist.size()>0)
    	 {
    		 fileDO = fileDOlist.get(0);
    	 }
    	 return FileUtils.inline(SAVEPATH+File.separator+fileDO.getPath(), fileDO.getName(), fileDO.getUuid(), fileDO.getExt(), request,response);
      }
      
      /**
    	 * 文件预览
    	 * 通过传递业务的id，找到对应的全部图片
    	 * @param typeid 业务的id
    	 * @param type 业务的对象字符串
    	 * eg:http://localhost:9090/file/getJsonByTypeImage/206/CommunityDO
    	 */
        @RequestMapping(value = "getJsonByTypeImage/{typeId}/{type}") 
        @ResponseBody
        public JsonResponseResultList<FileDO> getJsonByTypeImage(@PathVariable("typeId")Long typeId,@PathVariable("type")String type,HttpServletRequest request,HttpServletResponse response){   
        	try {
        		 //1.通过业务id 和 type 联合找到到对应的t_file的list
        		CoFileDO coFileDO = new CoFileDO();
        		coFileDO.setObjectA(Constants.COFILE_FILE);
        		coFileDO.setObjectB(type);
           	 	coFileDO.setObjectBId(typeId);
           	 	List<FileDO> fileDOlist =  fileService.getFileDOlistByCoFileDO(coFileDO);
        		return new JsonResponseResultList<FileDO>(fileDOlist);
            }catch (ServiceException e){
                e.printStackTrace();
                logger.error(e.getMessage());
                return new JsonResponseResultList<FileDO>(ResponseState.ERROR_CODE_SERVICE_ERROR.getCode(), e.getMessage());
            }
        	
        }

    
    
    
    
    
    /** 
     * 文件上传 
     * @param request {@link HttpServletRequest} 
     * @param response {@link HttpServletResponse} 
     * @return json response 
     */  
   @RequestMapping(value = "kindeditorfileUpload", method = RequestMethod.POST)  
   @ResponseBody  
   public Map<String, Object> kindeditorfileUpload(HttpServletRequest request, HttpServletResponse response) {  
       //文件保存本地目录路径  
       String savePath = SAVEPATH;  
       //文件保存目录URL  
       String saveUrl = request.getContextPath() + savePath.substring(2);  
 
       if(!ServletFileUpload.isMultipartContent(request)){  
           return getError("请选择文件。");  
       }  
       //检查目录  
       /*File uploadDir = new File(savePath); 
       if(!uploadDir.isDirectory()){ 
           return getError("上传目录不存在。"); 
       } 
       //检查目录写权限 
       if(!uploadDir.canWrite()){ 
           return getError("上传目录没有写权限。"); 
       }*/  
 
       String dirName = request.getParameter("dir");  
       if (dirName == null) {  
           dirName = "image";  
       }  
         
       //定义允许上传的文件扩展名  
       Map<String, String> extMap = new HashMap<String, String>();  
       extMap.put("image", "gif,jpg,jpeg,png,bmp");  
       extMap.put("flash", "swf,flv");  
       extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");  
       extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,xml,txt,zip,rar,gz,bz2");  
         
       if(!extMap.containsKey(dirName)){  
           return getError("目录名不正确。");  
       }  
       //创建文件夹  
       savePath += dirName + "/";  
       saveUrl += dirName + "/";  
       File saveDirFile = new File(savePath);  
       if (!saveDirFile.exists()) {  
           saveDirFile.mkdirs();  
       }  
         
       SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");  
       String ymd = sdf.format(new Date());  
       savePath += ymd + "/";  
       saveUrl += ymd + "/";  
       File dirFile = new File(savePath);  
       if (!dirFile.exists()) {  
           dirFile.mkdirs();  
       }  
         
       //最大文件大小  
       long maxSize = 1000000;  
         
       FileItemFactory factory = new DiskFileItemFactory();  
       ServletFileUpload upload = new ServletFileUpload(factory);  
       upload.setHeaderEncoding("UTF-8");  
       List<?> items = null;  
       try {  
           items = upload.parseRequest(request);  
       } catch (FileUploadException fe) {  
           return getError("接收文件异常。");  
       }  
       Iterator<?> itr = items.iterator();  
       while (itr.hasNext()) {  
           FileItem item = (FileItem) itr.next();  
           String fileName = item.getName();  
           if (!item.isFormField()) {  
               //检查文件大小  
               if(item.getSize() > maxSize){  
                   return getError("上传文件大小超过限制。");  
               }  
               //检查扩展名  
               String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();  
               if(!Arrays.<String>asList(extMap.get(dirName).split(",")).contains(fileExt)){  
                   return getError("上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。");  
               }  
 
               SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");  
               String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;  
               try{  
                   File uploadedFile = new File(savePath, newFileName);  
                   item.write(uploadedFile);  
               }catch(Exception e){  
                   return getError("上传文件失败。");  
               }  
                 
               Map<String, Object> succMap = new HashMap<String, Object>();  
               succMap.put("error", 0);  
               succMap.put("url", saveUrl + newFileName);  
               return succMap;  
           }  
       }  
         
       return null;  
   }  
 
   private Map<String, Object> getError(String errorMsg) {  
       Map<String, Object> errorMap = new HashMap<String, Object>();  
       errorMap.put("error", 1);  
       errorMap.put("message", errorMsg);  
       return errorMap;  
   }  
     
   /** 
     * 文件空间 
     * @param request {@link HttpServletRequest} 
     * @param response {@link HttpServletResponse} 
     * @return json 
     */  
   @RequestMapping(value = "kindeditorfileManager")  
   @ResponseBody  
   public Object kindeditorfileManager(HttpServletRequest request, HttpServletResponse response) {  
       //根目录路径，可以指定绝对路径  
       String rootPath = SAVEPATH;  
       //根目录URL，可以指定绝对路径，比如 http://www.yoursite.com/attached/  
       String rootUrl  = request.getContextPath() + rootPath.substring(2);  
       //图片扩展名  
       String[] fileTypes = new String[]{"gif", "jpg", "jpeg", "png", "bmp"};  
 
       String dirName = request.getParameter("dir");  
       if (dirName != null) {  
           if(!Arrays.<String>asList(new String[]{"image", "flash", "media", "file"}).contains(dirName)){  
               return "Invalid Directory name.";  
           }  
           rootPath += dirName + "/";  
           rootUrl += dirName + "/";  
           File saveDirFile = new File(rootPath);  
           if (!saveDirFile.exists()) {  
               saveDirFile.mkdirs();  
           }  
       }  
       //根据path参数，设置各路径和URL  
       String path = request.getParameter("path") != null ? request.getParameter("path") : "";  
       String currentPath = rootPath + path;  
       String currentUrl = rootUrl + path;  
       String currentDirPath = path;  
       String moveupDirPath = "";  
       if (!"".equals(path)) {  
           String str = currentDirPath.substring(0, currentDirPath.length() - 1);  
           moveupDirPath = str.lastIndexOf("/") >= 0 ? str.substring(0, str.lastIndexOf("/") + 1) : "";  
       }  
 
       //排序形式，name or size or type  
       String order = request.getParameter("order") != null ? request.getParameter("order").toLowerCase() : "name";  
 
       //不允许使用..移动到上一级目录  
       if (path.indexOf("..") >= 0) {  
           return "Access is not allowed.";  
       }  
       //最后一个字符不是/  
       if (!"".equals(path) && !path.endsWith("/")) {  
           return "Parameter is not valid.";  
       }  
       //目录不存在或不是目录  
       File currentPathFile = new File(currentPath);  
       if(!currentPathFile.isDirectory()){  
           return "Directory does not exist.";  
       }  
 
       //遍历目录取的文件信息  
       List<Map<String, Object>> fileList = new ArrayList<Map<String, Object>>();  
       if(currentPathFile.listFiles() != null) {  
           for (File file : currentPathFile.listFiles()) {  
               Hashtable<String, Object> hash = new Hashtable<String, Object>();  
               String fileName = file.getName();  
               if(file.isDirectory()) {  
                   hash.put("is_dir", true);  
                   hash.put("has_file", (file.listFiles() != null));  
                   hash.put("filesize", 0L);  
                   hash.put("is_photo", false);  
                   hash.put("filetype", "");  
               } else if(file.isFile()){  
                   String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();  
                   hash.put("is_dir", false);  
                   hash.put("has_file", false);  
                   hash.put("filesize", file.length());  
                   hash.put("is_photo", Arrays.<String>asList(fileTypes).contains(fileExt));  
                   hash.put("filetype", fileExt);  
               }  
               hash.put("filename", fileName);  
               hash.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));  
               fileList.add(hash);  
           }  
       }  
 
       if ("size".equals(order)) {  
           Collections.sort(fileList, new SizeComparator());  
       } else if ("type".equals(order)) {  
           Collections.sort(fileList, new TypeComparator());  
       } else {  
           Collections.sort(fileList, new NameComparator());  
       }  
       Map<String, Object> result = new HashMap<String, Object>();  
       result.put("moveup_dir_path", moveupDirPath);  
       result.put("current_dir_path", currentDirPath);  
       result.put("current_url", currentUrl);  
       result.put("total_count", fileList.size());  
       result.put("file_list", fileList);  
 
       return result;  
   }  
     
   private class NameComparator implements Comparator<Map<String, Object>> {  
       public int compare(Map<String, Object> hashA, Map<String, Object> hashB) {  
           if (((Boolean)hashA.get("is_dir")) && !((Boolean)hashB.get("is_dir"))) {  
               return -1;  
           } else if (!((Boolean)hashA.get("is_dir")) && ((Boolean)hashB.get("is_dir"))) {  
               return 1;  
           } else {  
               return ((String)hashA.get("filename")).compareTo((String)hashB.get("filename"));  
           }  
       }  
   }  
     
   private class SizeComparator implements Comparator<Map<String, Object>> {  
       public int compare(Map<String, Object> hashA, Map<String, Object> hashB) {  
           if (((Boolean)hashA.get("is_dir")) && !((Boolean)hashB.get("is_dir"))) {  
               return -1;  
           } else if (!((Boolean)hashA.get("is_dir")) && ((Boolean)hashB.get("is_dir"))) {  
               return 1;  
           } else {  
               if (((Long)hashA.get("filesize")) > ((Long)hashB.get("filesize"))) {  
                   return 1;  
               } else if (((Long)hashA.get("filesize")) < ((Long)hashB.get("filesize"))) {  
                   return -1;  
               } else {  
                   return 0;  
               }  
           }  
       }  
   }  
     
   private class TypeComparator implements Comparator<Map<String, Object>> {  
       public int compare(Map<String, Object> hashA, Map<String, Object> hashB) {  
           if (((Boolean)hashA.get("is_dir")) && !((Boolean)hashB.get("is_dir"))) {  
               return -1;  
           } else if (!((Boolean)hashA.get("is_dir")) && ((Boolean)hashB.get("is_dir"))) {  
               return 1;  
           } else {  
               return ((String)hashA.get("filetype")).compareTo((String)hashB.get("filetype"));  
           }  
       }  
   }  


}
